#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
import os
from rest_framework.pagination import PageNumberPagination
from rest_framework.decorators import action
from rest_framework import mixins
from rest_framework import viewsets
from django_filters.rest_framework import DjangoFilterBackend

# from rest_framework import serializers
from rest_framework import status
from apps.plan.models import Plan
from apps.plan.models import PlanCase
from apps.steps.models import Steps
from apps.case.models import Case
from apps.plan.serializers import PlanSerializers, PlanListSerializers, PlanCaseSerializer, PlanCaseListSerializer, \
    PlanCaseAddSerializer
from apps.report.serializers import ReportSerializers
from apps.case.serializers import CaseResultSerializers, CaseSerializers
from utils.rest.views import CustomViewBase
from utils.rest.response import JsonResponse
from utils.main.run import run

import logging

logger = logging.getLogger('log')


class PlanPagination(PageNumberPagination):
    """
    测试项目列表自定义分页
    """

    # 默认每页显示的个数
    page_size = 10
    # 可以动态改变每页显示的个数
    page_size_query_param = 'limit'
    # 页码参数
    page_query_param = 'page'
    # 最多能显示多少页
    max_page_size = 100


class PlanViewSet(CustomViewBase):
    """
    测试计划视图

    """
    queryset = Plan.objects.all().order_by('id')
    # serializer_class = PlanSerializers
    # 分页
    pagination_class = PlanPagination
    filter_backends = (DjangoFilterBackend,)
    filter_fields = ('project',)
    search_fields = ('name',)

    def get_serializer_class(self):
        if self.action == 'list':
            return PlanListSerializers
        else:
            return PlanSerializers

    @action(methods=['get'], detail=False)
    def count(self, request):
        count = Plan.objects.count()
        return JsonResponse(data={'count': count}, msg='success', code=200)

    @action(methods=['post'], detail=True)
    def execute(self, request, pk=None):
        """
        :param request:
        :param pk:
        :return:
        """
        plan_id = pk
        case_ids = []
        cases = PlanCase.objects.filter(plan=int(plan_id))
        if len(cases):
            for c in cases:
                case_ids.append(c.case.id)
            logger.debug('关联case：{}'.format(cases))
        else:
            return JsonResponse(code=100, msg='测试计划未关联用例', status=200)
        # 生成测试数据文件
        plan_name = Plan.objects.filter(id=plan_id)[0].name
        data = {}
        for case_id in case_ids:
            temp_dict = {}
            case_name = PlanCase.objects.filter(case_id=case_id)[0].case_name
            case_num = PlanCase.objects.filter(case_id=case_id)[0].case_num
            case_detail = PlanCase.objects.filter(case_id=case_id)[0].case_detail
            case_detail_obj = json.loads(case_detail)
            for obj in case_detail_obj:
                format_data_dict(obj)
            case_name = '_'.join([case_num, case_name, str(case_id)])
            temp_dict['name'] = case_name
            temp_dict['id'] = case_id
            temp_dict['steps'] = case_detail_obj
            data[case_name] = temp_dict
        file_name = 'test_data_{}.json'.format(plan_name)
        logger.debug('测试数据文件： {}'.format(file_name))
        with open(file_name, 'w', encoding='utf-8') as f:
            json.dump(data, f)
        # 执行测试
        all_results, summaries, report_path = run(plan_name)
        logger.debug('测试结果集合：{}'.format(all_results))
        if all_results:
            logger.debug('测试结果： {}'.format(summaries))
            logger.debug('测试报告路径: {}'.format(report_path))
            name = os.path.splitext(os.path.split(report_path)[1])[0]
            path = os.path.split(report_path)[1]
            report_data = {
                'name': name,
                'total': summaries['utils.main.main_test.MainTest']['total'],
                'success': summaries['utils.main.main_test.MainTest']['success'],
                'fail': summaries['utils.main.main_test.MainTest']['failure'] or summaries['utils.main.main_test.MainTest']['error'],
                'plan': plan_id,
                'report_path': path
            }
            logger.debug('report_data: {}'.format(report_data))
            r = ReportSerializers(data=report_data)
            if r.is_valid():
                r_instance = r.save()
                print("r_instance: {}".format(r_instance))
                save_case_result(all_results, r_instance.id)
                return JsonResponse(code=200, msg='执行完成; 保存报告成功', data=r.data, status=200)
            else:
                logger.debug('error: {}'.format(r.errors))
                return JsonResponse(data=[], msg=r.errors, code=100, status=status.HTTP_400_BAD_REQUEST,)
        else:
            return JsonResponse(code=100, msg='没有可执行的用例', status=200)


def save_case_result(all_results, report_id):
    for test_case_name, test_results in all_results.items():
        if test_results:
            for test_case in test_results:
                name = test_case.test_id.split(".")[-1]
                logger.debug('用例名称： {}'.format(name))
                case_id = name.split('_')[-1]
                logger.debug('用例id： {}'.format(case_id))
                logger.debug(('用例结果： {}'.format(test_case.outcome)))
                result = test_case.outcome
                log = ''
                if test_case.stdout or test_case.err:
                    logger.debug('执行信息： {}'.format(test_case.stdout))
                    log = test_case.stdout
                if test_case.err:
                    logger.debug('错误信息： {}'.format(test_case.err))
                    log = log + ''.join('%s' % e for e in list(test_case.err))
                data = {
                    'name': name,
                    'report': report_id,
                    'result': result,
                    'log': log
                }
                case_obj = Case.objects.get(id=case_id)
                c = CaseSerializers(instance=case_obj, data={'status': result}, partial=True)
                if c.is_valid():
                    c.save()
                else:
                    logger.debug('保存用例结果异常： {}'.format(c.errors))
                s = CaseResultSerializers(data=data)
                if s.is_valid():
                    logger.debug('用例【{}】 执行结果数据：{}'.format(name, s))
                    s.save()
                else:
                    logger.debug('保存执行结果异常： {}'.format(s.errors))


def is_json(json_str):
    """
    verify json_str is or not json string
    """
    try:
        json_obj = json.loads(json_str)
    except ValueError:
        return False
    return True


def format_data_dict(data):
    if isinstance(data, dict):
        for k, v in data.items():
            if isinstance(v, str) and is_json(v):
                data[k] = json.loads(v)


class PlanCaseViewSet(CustomViewBase):
    """
    测试计划-用例视图
    """
    queryset = PlanCase.objects.all().order_by('-edit_time')
    serializer_class = PlanCaseSerializer
    filter_backends = (DjangoFilterBackend,)
    filter_fields = ('plan',)
    pagination_class = PlanPagination

    search_fields = ('name',)

    def get_serializer_class(self):
        if self.action == 'list':
            return PlanCaseListSerializer
        else:
            return PlanCaseSerializer

    @action(methods=['post'], detail=True)
    def add_cases_to_plan(self, request, pk):
        plan_obj = Plan.objects.get(id=pk)
        caseIds = request.data['caseIds']
        from django.core import serializers
        plan_case_list = []
        for caseId in caseIds:
            if PlanCase.objects.filter(plan=pk, case=caseId):
                caseIds.remove(caseId)
                return JsonResponse(code=100, msg='id:{}已经被关联'.format(caseId), status=200)
            else:
                steps = serializers.serialize("json", Steps.objects.filter(case=caseId).order_by('step_num'))
                if len(steps):
                    step_obj = json.loads(steps)
                    for s in range(len(step_obj)):
                        step_obj[s] = step_obj[s]['fields']
                    case_detail = json.dumps(step_obj)
                    case_obj = Case.objects.get(id=caseId)
                    plan_case_list.append(
                        PlanCase(plan=plan_obj, case=case_obj, case_detail=case_detail, case_name=case_obj.name,
                                 case_num=case_obj.case_num)
                    )
        PlanCase.objects.bulk_create(plan_case_list)
        return JsonResponse(code=200, msg='success', status=200)


class PlanCaseCreateViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet):
    queryset = PlanCase.objects.all()
    serializer_class = PlanCaseAddSerializer
